package com.redis.lock;

import com.redis.annotation.CacheField;
import com.redis.annotation.CacheLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description
 * @Author lizhilong
 * @Date 2020/12/9 16:51
 */
@Slf4j
@Component
public class SpelKeyGenerator implements KeyGenerator {


    private static final String DELIMITER = "_";


    @Override
    public String getLockKey(ProceedingJoinPoint pjp) {

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock lockAnnotation = method.getAnnotation(CacheLock.class);
        final Object[] args = pjp.getArgs();
        final Parameter[] parameters = method.getParameters();
        String[] keys = lockAnnotation.keys();

        List<Object> paramList = new ArrayList<>(args.length);
        for (int i = 0; i < parameters.length; i++) {
            final CacheField annotation = parameters[i].getAnnotation(CacheField.class);
            if (annotation == null) {
                continue;
            }
            paramList.add(args[i]);
        }
        try {
            String keysValue = getKeysValue(keys, paramList);
            return lockAnnotation.prefix() + keysValue;
        } catch (Exception e) {
            log.error("生成key 失败,{}", e.getMessage());
            throw new IllegalArgumentException("key 表达式书写有误");
        }
    }

    private String getKeysValue(String[] keys, List<Object> paramList) throws Exception {
        if (CollectionUtils.isEmpty(paramList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (String key : keys) {
            String[] keySplit = key.split("\\.");
            for (Object object : paramList) {
                if (object.getClass().getSimpleName().equals(keySplit[0])) {
                    Field[] declaredFields = object.getClass().getDeclaredFields();
                    for (Field field : declaredFields) {
                        if (field.getName().equals(keySplit[1])) {
                            field.setAccessible(true);
                            Object o = field.get(object);
                            builder.append(DELIMITER).append(String.valueOf(o));
                        }
                    }

                }
            }
        }
        return builder.toString();
    }

}
